package com.lyf.scm.plan.domain.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.PageInfo;
import com.lyf.scm.common.constants.CommonConstants;
import com.lyf.scm.common.enums.*;
import com.lyf.scm.common.model.ExcelExportDataDTO;
import com.lyf.scm.common.util.AdvancedSearchUtil;
import com.lyf.scm.common.util.ExcelExportUtil;
import com.lyf.scm.common.util.date.MyDateUtil;
import com.lyf.scm.common.util.style.GeneralCellWriteHandler;
import com.lyf.scm.plan.api.dto.*;
import com.lyf.scm.plan.domain.convertor.DemandPlanConvertor;
import com.lyf.scm.plan.domain.remote.basedata.dto.ChannelInfoDTO;
import com.lyf.scm.plan.domain.remote.basedata.facade.BaseDataFacade;
import com.lyf.scm.plan.domain.remote.bigdata.dto.BigDataGeneralInfoDTO;
import com.lyf.scm.plan.domain.remote.item.dto.SearchPriceParamDTOS;
import com.lyf.scm.plan.domain.remote.item.dto.SkuSalePriceResultDTO;
import com.lyf.scm.plan.domain.remote.item.dto.SkuUnitDTO;
import com.lyf.scm.plan.domain.remote.item.facade.ItemCoreFacade;
import com.lyf.scm.plan.domain.remote.purchase.dto.PlanPoInfoDTO;
import com.lyf.scm.plan.domain.remote.purchase.dto.PlanPoQueryDTO;
import com.lyf.scm.plan.domain.remote.purchase.facade.PurchaseFacade;
import com.lyf.scm.plan.domain.remote.stock.dto.*;
import com.lyf.scm.plan.domain.remote.stock.facade.StockCoreFacade;
import com.lyf.scm.plan.domain.repository.*;
import com.lyf.scm.plan.domain.service.DemandPlanService;
import com.lyf.scm.plan.insfrastructure.db.dataobject.DemandPlanDO;
import com.lyf.scm.plan.insfrastructure.db.dataobject.bigdata.DirectlyStoreInDO;
import com.lyf.scm.plan.insfrastructure.db.dataobject.bigdata.SafetyStockUpDO;
import com.rome.arch.core.exception.RomeException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.lyf.scm.common.util.BatchHandlerUtil.splitTo;
import static com.lyf.scm.plan.domain.util.BigDataCacheUtil.endTime;
import static com.lyf.scm.plan.domain.util.BigDataCacheUtil.startTime;

/**
 * description:
 * 需求计划
 *
 * @author: 李兵兵
 * @data: 2020/8/7 16:30
 */
@Slf4j
@Service
public class DemandPlanServiceImpl implements DemandPlanService {
    @Resource
    private DemandPlanRepository demandPlanRepository;
    @Resource
    private ItemCoreFacade itemCoreFacade;
    @Resource
    private SalesPlanDirectlyRepository salesPlanDirectlyRepository;
    @Resource
    private SalesPlanOtherRespository salesPlanOtherRespository;
    @Resource
    private DemandPlanConvertor demandPlanConvertor;
    @Resource
    private RolePermissionsRepository rolePermissionsRepository;
    @Resource
    private RoleAuthorityAreaRepository roleAuthorityAreaRepository;
    @Resource
    private SalesPlanDirectlyInfoRepository salesPlanDirectlyInfoRepository;
    @Resource
    private PurchaseFacade purchaseFacade;
    @Resource
    private StockCoreFacade stockCoreFacade;
    @Resource
    private BaseDataFacade baseDataFacade;
    @Resource
    private OperationLogRecordRepository operationLogRecordRepository;


    /**
     * 按条件查询需求计划
     *
     * @param demandPlan
     * @return
     */
    @Override
    public PageInfo<DemandPlanInfoDTO> listWeekBySelective(DemandPlanDTO demandPlan) {
        //处理开始时间
        demandPlan.setStartTime(MyDateUtil.dealBeginDate(demandPlan.getStartTime()));
        //根据日期获取间隔日期集合,没有结束时间，默认14周
        List<Map<String, Date>> weekDates = MyDateUtil.getWeekDates(demandPlan.getStartTime(), CommonConstants.WEEK_SIZE);
        demandPlan.setWeekDateList(weekDates);
        //设置结束时间
        demandPlan.setEndTime(MyDateUtil.getLastDate(null, weekDates));
        PageInfo<DemandPlanInfoDTO> dtoPageInfo = new PageInfo<>();
        Long userId = demandPlan.getCreator();
        //获取当前用户角色权限
        List<RoleAuthorityAreaDTO> roleAreaList = roleAuthorityAreaRepository.listByUserId(userId);
        if (CollectionUtils.isEmpty(roleAreaList)) {
            throw new RomeException(ResponseMsg.FAIL_2004.getCode(), ResponseMsg.FAIL_2004.getMsg());
        }
        //渠道不为空为其他渠道计划用户
        roleAreaList = roleAreaList.stream().filter(item -> ObjectUtil.isNotNull(item.getChannelCode())).collect(Collectors.toList());
        List<String> channels = new ArrayList<>();
        roleAreaList.forEach(item -> {
            String channel = item.getChannelCode();
            channels.add(channel);
        });
        //高级搜索不选择渠道，查询用户对应渠道
        // if (CollectionUtils.isEmpty(demandPlan.getFatherChannelCodeList())) {
        //     demandPlan.setFatherChannelCodeList(channels);
        // }
        //根据高级搜索条件查询分页后的某一页的需要查询指标的信息
        PageInfo<DemandPlanDO> listPageInfo = demandPlanRepository.listWeekBySelective(demandPlan);
        List<DemandPlanDO> list = listPageInfo.getList();
        //查询对应的指标
        if (CollectionUtils.isNotEmpty(list)) {
            //处理查询出来的条数和数据，查询明细指标的条件
            DemandPlanDO demandPlanDO = dealData(list, demandPlan);
            //根据分页查询出来的数据，查询对应13周的数据
            List<DemandPlanDTO> demandPlanDOS = demandPlanRepository.listSalesAndDirectTarget(demandPlanDO);
            //获取对应的skuCode，换算单位使用
            List<String> skuCodeList = demandPlanDOS.stream().map(DemandPlanDTO::getSkuCode).distinct().collect(Collectors.toList());
            //处理单位
            //List<SkuUnitDTO> skuUnitList = itemCoreFacade.getConversionRatio(skuCodeList, demandPlan.getUnitType());
            //根据获取的换算比例计算指标数量
            //this.calculationPro(demandPlanDOS, skuUnitList);
            //获取所有查询条件标识
            List<String> conditions = this.getConditions(demandPlan);
            //第二次查询明细的时候由于需要对skuCode进行换算，所以，查询的是所有的skuCode,因此需要分组为第一个分页查询出来的条数
            this.getGroupByKey(demandPlanDOS, demandPlan.getSkuCodeList(), conditions);

            //处理判断是否含有品类和sku以及区域的条件
            PlanPoQueryDTO planPoQueryDTO = this.dealCategoryCode(demandPlan, demandPlanDOS, conditions);
            //预约采购量
            List<PlanPoInfoDTO> appointment = purchaseFacade.listAppointmentQty(planPoQueryDTO);
            //未履约采购量
            List<PlanPoInfoDTO> noAgreement = purchaseFacade.listNoAgreementQty(planPoQueryDTO);
            //查询实时库存 实时库存只有当前周才有库存，其他周没有，显示为-
            this.dealRealTimeStock(demandPlanDOS, demandPlan);
            //此时的采购中心传递过来的数量是采购单位,需要转为和传入的单位一样的数量
            appointment = this.dealPurchaseUnitType(appointment, demandPlan.getUnitType(), DemandPlanTargetEnum.RESERVE_PURCHASE_QTY.getColumns());
            noAgreement = this.dealPurchaseUnitType(noAgreement, demandPlan.getUnitType(), DemandPlanTargetEnum.NO_FULFIL_PURCHASE_QTY.getColumns());
            //得到分组后每组对应的14周的数据
            Map<String, Map<Date, BigDecimal>> appointmentMap = this.dealAppointmentAndNoAgreement(appointment, conditions, demandPlan, DemandPlanTargetEnum.RESERVE_PURCHASE_QTY.getColumns());
            Map<String, Map<Date, BigDecimal>> noAgreementMap = this.dealAppointmentAndNoAgreement(noAgreement, conditions, demandPlan, DemandPlanTargetEnum.NO_FULFIL_PURCHASE_QTY.getColumns());
            //将数据分组
            Map<String, List<DemandPlanDTO>> collect = demandPlanDOS.stream().collect(Collectors.groupingBy(DemandPlanDTO::getCondition, Collectors.toList()));
            //判断查询出来的条件是否包含区域，品类或者sku，如果不包含即不用分组，计算总量即可
            List<DemandPlanInfoDTO> targetList = this.getTargetList(collect, demandPlan);
            //把预约采购量 和 未履约采购量指标放入进去
            //处理分组后的数据
            dtoPageInfo.setList(this.dealGroupTarget(targetList, appointmentMap, noAgreementMap, weekDates, conditions));
            dtoPageInfo.setTotal(collect.values().size());
        }
        return dtoPageInfo;
    }

    /**
     * 处理实时库存，实时库存，只显示当前周的库存
     * 如果只对应上渠道，不显示此指标
     *
     * @param demandPlanDOS 列表
     */
    private List<DemandPlanDTO> dealRealTimeStock(List<DemandPlanDTO> demandPlanDOS, DemandPlanDTO demandPlanDTO) {
        QueryRealTimeStockDTO queryRealTimeStockDTO = new QueryRealTimeStockDTO();
        //条件编码集合
        queryRealTimeStockDTO.setBusinessType(RealTimeStockEnum.STORE_CODE.getType());
        List<String> codeList = demandPlanDOS.stream().map(DemandPlanDTO::getStoreCode).distinct().collect(Collectors.toList());
        //商品编码集合
        List<String> skuCodeList = demandPlanDOS.stream().map(DemandPlanDTO::getSkuCode).distinct().collect(Collectors.toList());
        queryRealTimeStockDTO.setCodeList(codeList);
        queryRealTimeStockDTO.setSkuCodeList(skuCodeList);
        //返回对应的每个门店和sku对应的库存
        List<RealTimeStockDTO> realTimeStockDTOS = stockCoreFacade.listAvailableQty(queryRealTimeStockDTO);
        demandPlanDOS.forEach(item -> {
            //门店加sku原则上应该是唯一的一条数据
            List<RealTimeStockDTO> stockDTOS = realTimeStockDTOS.stream().filter(rel -> (rel.getRealWarehouseOutCode() + rel.getSkuCode()).
                    equals(item.getStoreCode() + item.getSkuCode())).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(stockDTOS)) {
                item.setRealTimeInventoryQty(BigDecimal.ZERO);
            } else {
                item.setRealTimeInventoryQty(stockDTOS.stream().map(RealTimeStockDTO::getAvailableQty).reduce(BigDecimal.ZERO, BigDecimal::add));
            }
        });
        return demandPlanDOS;
    }

    @Override
    public ExcelExportDataDTO exportExcel(DemandPlanDTO demandPlanDTO, Integer type) {
        //指标名称集合
        List<String> allTargetsDesc = DemandPlanTargetEnum.getAllTargetsDesc();
        //获取日期标题
        List<String> dateTitles = MyDateUtil.processCyclesDate(demandPlanDTO.getWeekDateList(), "MM.dd");
        List<DemandPlanDTO> demandPlanDTOList = new ArrayList<>();
        List<List<Object>> exportDataList = null;
        Long userId = demandPlanDTO.getCreator();
        //获取当前用户角色权限
        List<RoleAuthorityAreaDTO> roleAreaList = roleAuthorityAreaRepository.listByUserId(userId);
        if (CollectionUtils.isEmpty(roleAreaList)) {
            throw new RomeException(ResponseMsg.FAIL_2004.getCode(), ResponseMsg.FAIL_2004.getMsg());
        }
        //渠道不为空为其他渠道计划用户
        roleAreaList = roleAreaList.stream().filter(item -> ObjectUtil.isNotNull(item.getChannelCode())).collect(Collectors.toList());
        List<String> channels = new ArrayList<>();
        roleAreaList.forEach(item -> {
            String channel = item.getChannelCode();
            channels.add(channel);
        });
        //高级搜索不选择渠道，查询用户对应渠道
        // if (CollectionUtils.isEmpty(demandPlanDTO.getFatherChannelCodeList())) {
        //     demandPlanDTO.setFatherChannelCodeList(channels);
        // }
        //全部数据导出
        if (ExcelExportTypeEnum.SEARCHED_DATA_EXPORT.getType().equals(type)) {
            demandPlanDTOList = demandPlanRepository.listAllByCondition(demandPlanDTO);
        }
        //当前页数据导出
        if (ExcelExportTypeEnum.CURRENT_PAGE_EXPORT.getType().equals(type)) {
            List<DemandPlanDO> list = demandPlanRepository.listWeekBySelective(demandPlanDTO).getList();
            if (ObjectUtil.isNotEmpty(list)) {
                DemandPlanDO demandPlanDO = dealData(list, demandPlanDTO);
                demandPlanDTOList = demandPlanRepository.listSalesAndDirectTarget(demandPlanDO);
            }
        }
        //导出选中的数据
        if (ExcelExportTypeEnum.CHECKED_BOX_EXPORT.getType().equals(type)) {
            DemandPlanDO demandPlanDO = dealData(demandPlanConvertor.dtoToDO(demandPlanDTO.getDemandPlanDTOS()), demandPlanDTO);
            demandPlanDTOList = demandPlanRepository.listSalesAndDirectTarget(demandPlanDO);
        }
        if (CollectionUtils.isEmpty(demandPlanDTOList)) {
            throw new RomeException(ResponseMsg.FAIL_2005.getCode(), ResponseMsg.FAIL_2005.getMsg());
        }
        //实际收货量
        this.dealRealTimeStock(demandPlanDTOList, demandPlanDTO);
        /*List<String> skuCodeList = new ArrayList<>();
        demandPlanDTOList.forEach(item -> skuCodeList.add(item.getSkuCode()));
        //处理单位
        List<SkuUnitDTO> skuUnitList = itemCoreFacade.getConversionRatio(skuCodeList, demandPlanDTO.getUnitType());
        this.calculationPro(demandPlanDTOList, skuUnitList);*/
        //获取所有查询条件标识
        List<String> conditions = this.getConditions(demandPlanDTO);
        //设置分组依据的key值
        this.getGroupByKey(demandPlanDTOList, demandPlanDTO.getSkuCodeList(), conditions);
        //将数据分组
        Map<String, List<DemandPlanDTO>> paramMap = demandPlanDTOList.stream().collect(Collectors.groupingBy(DemandPlanDTO::getCondition, Collectors.toList()));
        //处理判断是否含有品类和sku以及区域的条件
        PlanPoQueryDTO planPoQueryDTO = this.dealCategoryCode(demandPlanDTO, demandPlanDTOList, conditions);
        //预约采购量
        List<PlanPoInfoDTO> appointment = purchaseFacade.listAppointmentQty(planPoQueryDTO);
        //未履约采购量
        List<PlanPoInfoDTO> noAgreement = purchaseFacade.listNoAgreementQty(planPoQueryDTO);
        //此时的采购中心传递过来的数量是采购单位,需要转为和传入的单位一样的数量
        appointment = this.dealPurchaseUnitType(appointment, demandPlanDTO.getUnitType(), DemandPlanTargetEnum.RESERVE_PURCHASE_QTY.getColumns());
        noAgreement = this.dealPurchaseUnitType(noAgreement, demandPlanDTO.getUnitType(), DemandPlanTargetEnum.NO_FULFIL_PURCHASE_QTY.getColumns());
        //得到分组后每组对应的14周的数据
        Map<String, Map<Date, BigDecimal>> appointmentMap = this.dealAppointmentAndNoAgreement(appointment, conditions, demandPlanDTO, DemandPlanTargetEnum.RESERVE_PURCHASE_QTY.getColumns());
        Map<String, Map<Date, BigDecimal>> noAgreementMap = this.dealAppointmentAndNoAgreement(noAgreement, conditions, demandPlanDTO, DemandPlanTargetEnum.NO_FULFIL_PURCHASE_QTY.getColumns());
        List<DemandPlanInfoDTO> targetList = this.getTargetList(paramMap, demandPlanDTO);
        this.dealGroupTarget(targetList, appointmentMap, noAgreementMap, demandPlanDTO.getWeekDateList(), conditions);
        //全部数据导出
        exportDataList = this.getExcelTargetList(targetList, allTargetsDesc, dateTitles);
        //获取excel标题 同时返回高级搜索标题的数量
        List<List<String>> heads = new ArrayList<>();
        int mergeCellsColumns = this.setExcelTitles(heads, conditions, dateTitles);
        return ExcelExportUtil.getExcelExportData(mergeCellsColumns, exportDataList, heads, allTargetsDesc.size(), new GeneralCellWriteHandler());
    }


    /**
     * 把对应的未履约采购量和采购在途量放入对应的分组中
     */
    private List<DemandPlanInfoDTO> dealGroupTarget(List<DemandPlanInfoDTO> targetList, Map<String, Map<Date, BigDecimal>> appointmentMap,
                                                    Map<String, Map<Date, BigDecimal>> noAgreementMap, List<Map<String, Date>> weekDates,
                                                    List<String> conditions) {
        targetList.forEach(item -> {
            List<BigDecimal> appointmentQty = new ArrayList<>();
            List<BigDecimal> noAgreementQty = new ArrayList<>();
            //判断此组是否查询到结果，没有的话补0,存在结果，把结果代入进去
            if(CollectionUtil.isNotEmpty(appointmentMap)){
                Map<Date, BigDecimal> appointmentDateMap = appointmentMap.get(this.groupKeys(conditions, item));
                if (ObjectUtil.isEmpty(appointmentDateMap)) {
                    weekDates.forEach(date -> appointmentQty.add(BigDecimal.ZERO));
                } else {
                    appointmentQty.addAll(new ArrayList(appointmentMap.get(this.groupKeys(conditions, item)).values()));
                }
            }else{
                weekDates.forEach(date -> appointmentQty.add(BigDecimal.ZERO));
            }
            if(CollectionUtil.isNotEmpty(noAgreementMap)){
                Map<Date, BigDecimal> noAgreementDateMap = noAgreementMap.get(this.groupKeys(conditions, item));
                if (ObjectUtil.isEmpty(noAgreementDateMap)) {
                    weekDates.forEach(date -> noAgreementQty.add(BigDecimal.ZERO));
                } else {
                    noAgreementQty.addAll(new ArrayList<>(noAgreementMap.get(this.groupKeys(conditions, item)).values()));
                }
            }else{
                weekDates.forEach(date -> noAgreementQty.add(BigDecimal.ZERO));
            }
            item.setReservePurchaseQty(appointmentQty);
            item.setReservePurchaseQtyLabel(DemandPlanTargetEnum.RESERVE_PURCHASE_QTY.getDesc());
            item.setNoFulfilPurchaseQty(noAgreementQty);
            item.setNoFulfilPurchaseQtyLabel(DemandPlanTargetEnum.NO_FULFIL_PURCHASE_QTY.getDesc());
        });
        return targetList;
    }

    /**
     * 图表的指标
     *
     * @param demandPlan 需求计划
     * @return
     */
    @Override
    public List<DemandPlanInfoDTO> listAllByCycles(DemandPlanDTO demandPlan) {
        this.dealBeginAndEndTime(demandPlan);
        List<Map<String, Date>> weekDates = MyDateUtil.getWeekDates(demandPlan.getStartTime(), (int) DateUtil.betweenWeek(demandPlan.getStartTime(), demandPlan.getEndTime(), false));
        demandPlan.setWeekDateList(weekDates);
        Long userId = demandPlan.getCreator();
        //获取当前用户角色权限
        List<RoleAuthorityAreaDTO> roleAreaList = roleAuthorityAreaRepository.listByUserId(userId);
        if (CollectionUtils.isEmpty(roleAreaList)) {
            throw new RomeException(ResponseMsg.FAIL_2004.getCode(), ResponseMsg.FAIL_2004.getMsg());
        }
        //渠道不为空为其他渠道计划用户
        roleAreaList = roleAreaList.stream().filter(item -> ObjectUtil.isNotNull(item.getChannelCode())).collect(Collectors.toList());
        List<String> channels = new ArrayList<>();
        roleAreaList.forEach(item -> {
            String channel = item.getChannelCode();
            channels.add(channel);
        });
        //高级搜索不选择渠道，查询用户对应渠道
        // if (CollectionUtils.isEmpty(demandPlan.getFatherChannelCodeList())) {
        //     demandPlan.setFatherChannelCodeList(channels);
        // }
        List<DemandPlanDTO> demandPlanDTOS = demandPlanRepository.listAllByCycles(demandPlan);
        if (CollectionUtils.isNotEmpty(demandPlanDTOS)) {
            /*List<String> skuCodeList = new ArrayList<>();
            demandPlanDTOS.forEach(item -> skuCodeList.add(item.getSkuCode()));
            //处理单位
            List<SkuUnitDTO> skuUnitList = itemCoreFacade.getConversionRatio(skuCodeList, demandPlan.getUnitType());
            this.calculationPro(demandPlanDTOS, skuUnitList);*/
            //获取所有查询条件标识
            List<String> conditions = this.getConditions(demandPlan);
            //设置分组的key
            Map<String, List<DemandPlanDTO>> collect = demandPlanDTOS.stream().collect(Collectors.groupingBy(item -> CommonConstants.ONE.toString(), Collectors.toList()));
            //预约采购量
            PlanPoQueryDTO planPoQueryDTO = new PlanPoQueryDTO();
            planPoQueryDTO.setStartTime(demandPlan.getStartTime());
            planPoQueryDTO.setEndTime(demandPlan.getEndTime());
            List<PlanPoInfoDTO> appointment = purchaseFacade.listAppointmentQty(planPoQueryDTO);
            List<BigDecimal> appointmentQty = new ArrayList<>();
            List<BigDecimal> noAgreementQty = new ArrayList<>();
            this.dealChartTarget(appointment, appointmentQty, weekDates, DemandPlanTargetEnum.RESERVE_PURCHASE_QTY.getColumns());
            //未履约采购量
            List<PlanPoInfoDTO> noAgreement = purchaseFacade.listNoAgreementQty(planPoQueryDTO);
            this.dealChartTarget(noAgreement, noAgreementQty, weekDates, DemandPlanTargetEnum.NO_FULFIL_PURCHASE_QTY.getColumns());
            //实时库存
            this.dealRealTimeStock(demandPlanDTOS, demandPlan);
            //图标的指标集合的长度为1
            List<DemandPlanInfoDTO> targetList = this.getTargetList(collect, demandPlan);
            targetList.forEach(item -> {
                item.setReservePurchaseQty(appointmentQty);
                item.setReservePurchaseQtyLabel(DemandPlanTargetEnum.RESERVE_PURCHASE_QTY.getDesc());
                item.setNoFulfilPurchaseQty(noAgreementQty);
                item.setNoFulfilPurchaseQtyLabel(DemandPlanTargetEnum.NO_FULFIL_PURCHASE_QTY.getDesc());
            });
            return this.getTargetList(collect, demandPlan);
        } else {
            return null;
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer tidyData() {
        DemandPlanDTO demandPlan = new DemandPlanDTO();
        //处理开始和结束时间
        this.dealBeginAndEndTime(demandPlan);
        //分别去查询其他渠道和直营渠道的表，然后把数据插入到需求计划表中，每周插入一次，上周插入过的做更新，没有的插入
        //由于每个表中都有多个确认量，需求计划取得是最高级别的确认量
        //直营预测的，先去查询最高级别的对应的用户，根据用户id查询确认量和id，然后在对应上渠道，区域，编码等信息,
        List<RoleAuthorityAreaDTO> roleAuthorityAreaList = roleAuthorityAreaRepository.listByRoleId(
                rolePermissionsRepository.getPermissionByLevel(rolePermissionsRepository.getMaxLevel()).getId());
        List<SalesPlanDirectlyInfoDTO> infoDTOList = null;
        if (CollectionUtils.isNotEmpty(roleAuthorityAreaList)) {
            //根据用户id和时间查询对应的时间段，查询出用户id查询确认量和id
            List<Long> userIdList = roleAuthorityAreaList.stream().map(RoleAuthorityAreaDTO::getUserId).distinct().collect(Collectors.toList());
            infoDTOList = salesPlanDirectlyInfoRepository.listByUserId(userIdList, demandPlan.getStartTime(), demandPlan.getEndTime());
        }
        //如果查询不到，根据时间查询预测计划量，确认量为0
        List<SalesPlanDirectlyDTO> salesPlanDirectlyDTOS = salesPlanDirectlyRepository.listForestPlanQty(demandPlan);
        //比较上下两个数组存在差异，表示的是还有没有确认的量
        if (CollectionUtils.isNotEmpty(salesPlanDirectlyDTOS) && CollectionUtils.isNotEmpty(infoDTOList)) {
            for (SalesPlanDirectlyDTO salesPlanDirectlyDTO : salesPlanDirectlyDTOS) {
                for (SalesPlanDirectlyInfoDTO salesPlanDirectlyInfoDTO : infoDTOList) {
                    if(salesPlanDirectlyDTO.getId().equals(salesPlanDirectlyInfoDTO.getDirectlyId())){
                        salesPlanDirectlyDTO.setConfirmQty(salesPlanDirectlyInfoDTO.getConfirmQty());
                        salesPlanDirectlyDTO.setLastConfirmQty(salesPlanDirectlyInfoDTO.getLastConfirmQty());
                    }
                }
            }
        }
        //去查询其他渠道预测表
        List<SalesPlanOtherDTO> salesPlanOtherDTOList = salesPlanOtherRespository.listPlanOther(demandPlan);
        List<SalesPlanOtherDTO> salesPlanOtherDTOS = new ArrayList<>();
        //其他渠道预测表中，存在一个计划类型，所以会有渠道编码加sku加上门店加时间相同，此时表中的数据需要加起来
        if (CollectionUtils.isNotEmpty(salesPlanOtherDTOList)) {
            Map<String, List<SalesPlanOtherDTO>> listMap = salesPlanOtherDTOList.stream().collect(Collectors.groupingBy(item -> item.getChannelCode()
                    + item.getSkuCode() + item.getStoreCode() + item.getPlanStartDate(), Collectors.toList()));
            listMap.forEach((k, v) -> {
                //说明存在重复的数据，加起来
                if (v.size() > CommonConstants.ONE) {
                    BigDecimal planQty = v.stream().map(SalesPlanOtherDTO::getPlanQty).reduce(BigDecimal.ZERO, BigDecimal::add);
                    BigDecimal confirmQty = v.stream().map(SalesPlanOtherDTO::getAllchannelConfirmedQty).reduce(BigDecimal.ZERO, BigDecimal::add);
                    BigDecimal lastConfirmQty = v.stream().map(SalesPlanOtherDTO::getAllchannelLastConfirmedQty).reduce(BigDecimal.ZERO, BigDecimal::add);
                    v.get(0).setPlanQty(planQty);
                    v.get(0).setAllchannelConfirmedQty(confirmQty);
                    v.get(0).setAllchannelLastConfirmedQty(lastConfirmQty);
                    salesPlanOtherDTOS.add(v.get(0));
                } else {
                    salesPlanOtherDTOS.add(v.get(CommonConstants.ZERO));
                }
            });

        }
        //记录直营渠道和其他渠道相同的记录，只插入一次
        List<SalesPlanDirectlyDTO> directlyDTOS = new ArrayList<>();
        //只有直营的存在预测量，所以销售计划量是直营的同时间的预测量加上营销活动中心传递来的销售计划量
        if (CollectionUtils.isNotEmpty(salesPlanDirectlyDTOS) && CollectionUtils.isNotEmpty(salesPlanOtherDTOS)) {
            salesPlanDirectlyDTOS.forEach(item -> {
                salesPlanOtherDTOS.forEach(salesPlanOtherDTO -> {
                    String keys = item.getChannelCode() + item.getStoreCode() + item.getSkuCode() + item.getPlanStartDate();
                    String keyd = salesPlanOtherDTO.getChannelCode() + salesPlanOtherDTO.getStoreCode() + salesPlanOtherDTO.getSkuCode() +
                            salesPlanOtherDTO.getPlanStartDate();
                    //如果门店和sku加上计划开始时间相等，销售计划量就等于两个相加,上次确认量也要相加
                    if (keys.equals(keyd)) {
                        directlyDTOS.add(item);
                        salesPlanOtherDTO.setPlanQty(item.getForecastQty().add(salesPlanOtherDTO.getPlanQty()));
                        salesPlanOtherDTO.setAllchannelLastConfirmedQty((ObjectUtil.isEmpty(item.getLastConfirmQty()) ? BigDecimal.ZERO : item.getLastConfirmQty()).add(salesPlanOtherDTO.getAllchannelLastConfirmedQty()));
                        salesPlanOtherDTO.setForecastQty(item.getForecastQty());
                    }
                });
            });
        }
        //删除两个表中共同的数据
        salesPlanDirectlyDTOS.removeAll(directlyDTOS);
        List<DemandPlanDO> demandPlanDOS = dealDemandPlanDOS(salesPlanDirectlyDTOS, salesPlanOtherDTOS);
        Integer integer = 0;
        if (CollectionUtils.isNotEmpty(demandPlanDOS)) {
            //先查询出表中存在的数据，进行update
            //后筛选出表中不存在的数据，进行insert
            List<DemandPlanDO> updateList = new ArrayList<>();
            List<DemandPlanDO> insertList = new ArrayList<>();
            List<DemandPlanDO> demandPlanList = demandPlanRepository.listExistData(demandPlanDOS);
            if (ObjectUtil.isNotEmpty(demandPlanList)) {
                demandPlanList.forEach(item -> {
                    demandPlanDOS.forEach(demandPlanDO -> {
                        if (item.getOnlySaid().equals(demandPlanDO.getOnlySaid())) {
                            demandPlanDO.setVersionNo(item.getVersionNo());
                            updateList.add(demandPlanDO);
                        }
                    });
                });
            }
            demandPlanDOS.removeAll(updateList);
            insertList.addAll(demandPlanDOS);
            if (ObjectUtil.isNotEmpty(updateList)) {
                //由于数量过大，一次更新会导致不成功,所以分批插入
                int page = updateList.size() / PageSizeEnum.DEMAND_PLAN_NO.getCode() + 1;
                for (int i = 0; i < page; i++) {
                    if(i==page-1){
                        List<DemandPlanDO> planDOS = updateList.subList(PageSizeEnum.DEMAND_PLAN_NO.getCode() * i, updateList.size());
                        integer = demandPlanRepository.updateData(planDOS);
                    }else{
                        List<DemandPlanDO> planDOS = updateList.subList(PageSizeEnum.DEMAND_PLAN_NO.getCode() * i, PageSizeEnum.DEMAND_PLAN_NO.getCode() * (i + 1));
                        integer = demandPlanRepository.updateData(planDOS);
                    }
                }
            }
            if (ObjectUtil.isNotEmpty(insertList)) {
                //由于数量过大，一次更新会导致不成功,所以分批插入
                int page = insertList.size() / PageSizeEnum.DEMAND_PLAN_NO.getCode() + 1;
                for (int i = 0; i < page; i++) {
                    if(i==page-1){
                        List<DemandPlanDO> planDOS = insertList.subList(PageSizeEnum.DEMAND_PLAN_NO.getCode() * i, updateList.size());
                        integer = demandPlanRepository.saveData(planDOS);
                    }else{
                        List<DemandPlanDO> planDOS = insertList.subList(PageSizeEnum.DEMAND_PLAN_NO.getCode() * i, PageSizeEnum.DEMAND_PLAN_NO.getCode() * (i + 1));
                        integer = demandPlanRepository.saveData(planDOS);
                    }
                }
            }
        }
        return integer;
    }


    /**
     * Excel中的每条数据
     *
     * @param targetList
     * @param targets
     * @param dateTitles
     * @return
     */
    private List<List<Object>> getExcelTargetList(List<DemandPlanInfoDTO> targetList, List<String> targets, List<String> dateTitles) {
        //获取excel数据
        List<List<Object>> exportDataList = new ArrayList<>();
        targetList.forEach(item -> {
            for (int i = 0; i < targets.size(); i++) {
                List<Object> itemRow = new ArrayList<>();
                //加入渠道，区域，品类，商品  信息
                this.setExcelRowAdvancedSearchCondition(item, itemRow);
                //加入指标
                itemRow.add(targets.get(i));
                //加入数据
                for (int j = 0; j < dateTitles.size(); j++) {
                    //获取指标集合，这里没有排序，默认使用枚举的顺序
                    switch (i) {
                        case 0:
                            itemRow.add(item.getSalesPlanAmount().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getSalesPlanAmount().get(j));
                            break;
                        case 1:
                            itemRow.add(item.getForecastPlanAmount().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getForecastPlanAmount().get(j));
                            break;
                        case 2:
                            itemRow.add(item.getSalesPlanQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getSalesPlanQty().get(j));
                            break;
                        case 3:
                            itemRow.add(item.getForecastPlanQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getForecastPlanQty().get(j));
                            break;
                        case 4:
                            itemRow.add(item.getLastConfirmQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getLastConfirmQty().get(j));
                            break;
                        case 5:
                            itemRow.add(item.getSafetyStockQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getSafetyStockQty().get(j));
                            break;
                        case 6:
                            itemRow.add(item.getReservePurchaseQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getReservePurchaseQty().get(j));
                            break;
                        case 7:
                            itemRow.add(item.getActualSalesQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getActualSalesQty().get(j));
                            break;
                        case 8:
                            itemRow.add(item.getNoFulfilPurchaseQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getNoFulfilPurchaseQty().get(j));
                            break;
                        case 9:
                            itemRow.add(item.getRealTimeInventory().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getRealTimeInventory().get(j));
                            break;
                        default:
                            break;
                    }
                }
                exportDataList.add(itemRow);
            }
        });
        return exportDataList;
    }

    /**
     * 处理插入时对象的整理
     */
    private List<DemandPlanDO> dealDemandPlanDOS(List<SalesPlanDirectlyDTO> salesPlanDirectlyDTOS, List<SalesPlanOtherDTO> salesPlanOtherDTOS) {
        List<DemandPlanDO> demandPlanDOS = new ArrayList<>();
        //查询各渠道中sku对应的价格
        if (CollectionUtils.isNotEmpty(salesPlanDirectlyDTOS)) {
            salesPlanDirectlyDTOS.forEach(item -> {
                DemandPlanDO demandPlanDO = demandPlanConvertor.salesPlanDirectlyDtoToDO(item);
                demandPlanDO.setOnlySaid(DemandPlanEnum.DIRECTLY_CHANNEL.getColumns() + item.getId());
                demandPlanDO.setForecastPlanQty(item.getForecastQty());
                demandPlanDO.setForecastPlanAmount(item.getForecastQty().multiply(BigDecimal.TEN).setScale(3,BigDecimal.ROUND_HALF_UP ));
                demandPlanDO.setSalesPlanQty(item.getForecastQty());
                demandPlanDO.setSalesPlanAmount(item.getForecastQty().multiply(BigDecimal.TEN).setScale(3,BigDecimal.ROUND_HALF_UP));
                demandPlanDO.setModifier(SystemUserEnum.SYSTEM_USER.getCode());
                demandPlanDO.setModifierName(SystemUserEnum.SYSTEM_USER.getName());
                demandPlanDOS.add(demandPlanDO);
            });
        }
        if (CollectionUtils.isNotEmpty(salesPlanOtherDTOS)) {
            salesPlanOtherDTOS.forEach(item -> {
                DemandPlanDO demandPlanDO = demandPlanConvertor.salesPlanOtherDtoToDO(item);
                demandPlanDO.setOnlySaid(DemandPlanEnum.OTHER_CHANNEL.getColumns() + item.getId());
                demandPlanDO.setConfirmQty(item.getAllchannelConfirmedQty());
                demandPlanDO.setConfirmAmount(item.getConfirmedQty().multiply(BigDecimal.TEN));
                demandPlanDO.setLastConfirmQty(item.getAllchannelLastConfirmedQty());
                demandPlanDO.setSalesPlanQty(item.getPlanQty());
                demandPlanDO.setForecastPlanQty(item.getForecastQty());
                demandPlanDO.setSalesPlanAmount(item.getPlanQty().multiply(BigDecimal.TEN));
                demandPlanDO.setModifier(SystemUserEnum.SYSTEM_USER.getCode());
                demandPlanDO.setModifierName(SystemUserEnum.SYSTEM_USER.getName());
                demandPlanDOS.add(demandPlanDO);
            });
        }
        //表中只落销售单位
        List<String> list = demandPlanDOS.stream().map(DemandPlanDO::getSkuCode).distinct().collect(Collectors.toList());
        List<SkuUnitDTO> skuUnitDTOS = itemCoreFacade.getConversionRatio(list, (long) SkuUnitTypeEnum.SALES_UNIT.getUnitType());
        Map<String, SkuUnitDTO> unitDTOMap = skuUnitDTOS.stream().collect(Collectors.toMap(item -> item.getSkuCode(), item -> item));
        demandPlanDOS.forEach(item->{
            BigDecimal scale = BigDecimal.
                    valueOf(unitDTOMap.get(item.getSkuCode()).getScale());
            item.setForecastPlanQty(item.getForecastPlanQty().multiply(scale).setScale(CommonConstants.THREE_DECIMAL, BigDecimal.ROUND_HALF_UP));
            item.setSalesPlanQty(item.getSalesPlanQty().multiply(scale).setScale(CommonConstants.THREE_DECIMAL, BigDecimal.ROUND_HALF_UP));
            item.setConfirmQty(item.getConfirmQty().multiply(scale).setScale(CommonConstants.THREE_DECIMAL, BigDecimal.ROUND_HALF_UP));
            item.setLastConfirmQty(item.getLastConfirmQty().multiply(scale).setScale(CommonConstants.THREE_DECIMAL, BigDecimal.ROUND_HALF_UP));
        });
        return demandPlanDOS;
    }

    /**
     * 处理计算出对应的单价(所有渠道sku对应的单价)
     * 价格现在只有先根据鲲鹏的最小渠道映射中台的渠道，然后根据中台的渠道加skuCode，查询
     */
    private List<SkuSalePriceResultDTO> dealPrice(List<ChannelToSku> channelToSku){
        List<SkuSalePriceResultDTO> skuPrice = new ArrayList<>();
        //先根据对应的渠道批量查询子渠道
        List<String> channelCode = channelToSku.stream().map(ChannelToSku::getChannelCode).distinct().collect(Collectors.toList());
        //获取对应的子渠道
        List<ChannelInfoDTO> subChannelInfoDTOS = baseDataFacade.queryByParentChannels(channelCode);
        //根据子渠道和对应的sku查询
        List<SearchPriceParamDTOS> searchPriceParamDTOS=new ArrayList<>();
        //如果获取到的子渠道不为空,分开各个渠道的主编码
        if(CollectionUtils.isNotEmpty(subChannelInfoDTOS)){
            channelCode.forEach(item->{
                List<ChannelInfoDTO> list = subChannelInfoDTOS.stream().filter(sub -> sub.getParentChannel().equals(item)).collect(Collectors.toList());
                //如果list为空，代表此渠道没有子渠道
                if(CollectionUtils.isEmpty(list)){
                    List<String> skuCodes = channelToSku.stream().filter(channel -> channel.getChannelCode().equals(item)).findFirst().get().getSkuCodes();
                    skuCodes.forEach(sku->{
                        SearchPriceParamDTOS paramDTOS=new SearchPriceParamDTOS();
                        paramDTOS.setChannelCode(item);
                        paramDTOS.setSkuCode(sku);
                        searchPriceParamDTOS.add(paramDTOS);
                    });
                }
                //如果不为空，代表的是有子渠道,因为存在每个sku在每个渠道都有对应的价格了，所以去所有价格算平均值
                else{
                    List<String> skuCodes = channelToSku.stream().filter(channel -> channel.getChannelCode().equals(item)).findFirst().get().getSkuCodes();
                    list.forEach(channel->{
                        skuCodes.forEach(sku->{
                            SearchPriceParamDTOS paramDTOS=new SearchPriceParamDTOS();
                            paramDTOS.setChannelCode(channel.getChannel());
                            paramDTOS.setSkuCode(sku);
                            searchPriceParamDTOS.add(paramDTOS);
                        });
                    });
                }
            });
            //根据对应的子渠道和sku查询价格
            List<SkuSalePriceResultDTO> skuSalePriceResultDTOS = itemCoreFacade.selectSalePrice(searchPriceParamDTOS);
            Map<String, List<SkuSalePriceResultDTO>> listMap = skuSalePriceResultDTOS.stream().collect(Collectors.groupingBy(SkuSalePriceResultDTO::getChannelCode, Collectors.toList()));
            //原则上不可能为空的，此时写数据可以进行测试
            if(CollectionUtils.isEmpty(skuSalePriceResultDTOS)){
                channelCode.forEach(item->{
                    //获取当前渠道的子渠道
                    List<ChannelInfoDTO> list = subChannelInfoDTOS.stream().filter(sub -> sub.getParentChannel().equals(item)).collect(Collectors.toList());
                    //没有子渠道，此时价格就是对应的渠道价格
                    if(CollectionUtils.isEmpty(list)){
                        List<SkuSalePriceResultDTO> skuToPrice = skuSalePriceResultDTOS.stream().filter(sale -> sale.getChannelCode().equals(item)).collect(Collectors.toList());
                        //一个渠道有多个sku，取价格即可
                        skuToPrice.forEach(sku->{
                            SkuSalePriceResultDTO price=new SkuSalePriceResultDTO();
                            price.setChannelCode(item);
                            price.setSalePrice(sku.getSalePrice());
                            skuPrice.add(price);
                        });
                    }
                    //说明存在子渠道，取所有子渠道的价格的平均值
                    else{
                        //一个子渠道对应的所有的
                        List<SkuSalePriceResultDTO> resultDTOS=new ArrayList<>();
                        list.forEach(channel->{
                            List<SkuSalePriceResultDTO> collect = listMap.get(channel);
                            resultDTOS.addAll(collect);
                        });
                        //安照sku进行分组，可以得到所有sku的不同价格，取平均值
                        Map<String, List<SkuSalePriceResultDTO>> skuToSubChannel = resultDTOS.stream().collect(Collectors.groupingBy(SkuSalePriceResultDTO::getSkuCode, Collectors.toList()));
                        skuToSubChannel.forEach((k,v)->{
                            SkuSalePriceResultDTO price=new SkuSalePriceResultDTO();
                            //取出价格算平均值
                            BigDecimal allPrice = v.stream().map(SkuSalePriceResultDTO::getSalePrice).reduce(BigDecimal.ZERO, BigDecimal::add);
                            BigDecimal onlyPrice = allPrice.divide(new BigDecimal(v.size()), BigDecimal.ROUND_HALF_UP, 5);
                            price.setSalePrice(onlyPrice);
                            price.setChannelCode(item);
                            skuPrice.add(price);
                        });
                    }
                });
            }
        }
        return null;
    }


    /**
     * 处理时间
     */
    public DemandPlanDTO dealBeginAndEndTime(DemandPlanDTO demandPlan) {
        //如果开始时间为空
        if (ObjectUtil.isEmpty(demandPlan.getStartTime())) {
            demandPlan.setStartTime(DateUtil.beginOfWeek(new Date()));
        } else {
            demandPlan.setStartTime(DateUtil.beginOfWeek(demandPlan.getStartTime()));
        }
        //如果结束时间为空
        if (ObjectUtil.isEmpty(demandPlan.getEndTime())) {
            demandPlan.setEndTime(DateUtil.beginOfWeek(DateUtil.offsetWeek(new Date(), CommonConstants.WEEK_TARGET_SIZE)));
        } else {
            demandPlan.setEndTime(DateUtil.beginOfWeek(DateUtil.offsetWeek(demandPlan.getEndTime(), CommonConstants.ONE)));
        }
        return demandPlan;
    }

    /**
     * 汇总分组后的数据
     *
     * @param paramMap   参数映射
     * @param demandPlan 需求计划
     * @return {@link List<GmvTargetInfoDTO>}
     */
    private List<DemandPlanInfoDTO> getTargetList(Map<String, List<DemandPlanDTO>> paramMap, DemandPlanDTO demandPlan) {
        List<DemandPlanInfoDTO> demandPlantInfoList = new ArrayList<>();
        List<Map<String, Date>> weekDateList = demandPlan.getWeekDateList();
        //将分组后的数据汇总
        paramMap.keySet().forEach(key -> {
            DemandPlanInfoDTO demandPlanInfoDTO = new DemandPlanInfoDTO();
            List<BigDecimal> salesPlanAmount = new ArrayList<>();
            List<BigDecimal> forecastPlanAmount = new ArrayList<>();
            List<BigDecimal> salesPlanQty = new ArrayList<>();
            List<BigDecimal> forecastPlanQty = new ArrayList<>();
            List<BigDecimal> lastConfirmQty = new ArrayList<>();
            List<BigDecimal> safetyStockQty = new ArrayList<>();
            List<BigDecimal> actualSalesQty = new ArrayList<>();
            List<BigDecimal> realTimeInventory = new ArrayList<>();
            List<String> realTimeString = new ArrayList<>();
            // 设置销售计划金额
            weekDateList.forEach(date -> salesPlanAmount.add(paramMap.get(key).stream().filter(item -> item.getPlanStartDate().compareTo(date.get(DemandPlanEnum.START_TIME.getColumns())) == 0 && item.getPlanEndDate().compareTo(date.get(DemandPlanEnum.END_TIME.getColumns())) == 0).map(DemandPlanDTO::getSalesPlanAmount).reduce(BigDecimal.ZERO, BigDecimal::add)));
            demandPlanInfoDTO.setSalesPlanAmountLabel(DemandPlanTargetEnum.SALES_PLAN_AMOUNT.getDesc());
            demandPlanInfoDTO.setSalesPlanAmount(salesPlanAmount);
            // 设置预测计划金额
            weekDateList.forEach(date -> forecastPlanAmount.add(paramMap.get(key).stream().filter(item -> item.getPlanStartDate().compareTo(date.get(DemandPlanEnum.START_TIME.getColumns())) == 0 && item.getPlanEndDate().compareTo(date.get(DemandPlanEnum.END_TIME.getColumns())) == 0).map(DemandPlanDTO::getForecastPlanAmount).reduce(BigDecimal.ZERO, BigDecimal::add)));
            demandPlanInfoDTO.setForecastPlanAmountLabel(DemandPlanTargetEnum.FORECAST_PLAN_AMOUNT.getDesc());
            demandPlanInfoDTO.setForecastPlanAmount(forecastPlanAmount);
            // 设置销售计划量
            weekDateList.forEach(date -> salesPlanQty.add(paramMap.get(key).stream().filter(item -> item.getPlanStartDate().compareTo(date.get(DemandPlanEnum.START_TIME.getColumns())) == 0 && item.getPlanEndDate().compareTo(date.get(DemandPlanEnum.END_TIME.getColumns())) == 0).map(DemandPlanDTO::getSalesPlanQty).reduce(BigDecimal.ZERO, BigDecimal::add)));
            demandPlanInfoDTO.setSalesPlanQtyLabel(DemandPlanTargetEnum.SALES_PLAN_QTY.getDesc());
            demandPlanInfoDTO.setSalesPlanQty(salesPlanQty);
            // 设置预测计划量
            weekDateList.forEach(date -> forecastPlanQty.add(paramMap.get(key).stream().filter(item -> item.getPlanStartDate().compareTo(date.get(DemandPlanEnum.START_TIME.getColumns())) == 0 && item.getPlanEndDate().compareTo(date.get(DemandPlanEnum.END_TIME.getColumns())) == 0).map(DemandPlanDTO::getForecastPlanQty).reduce(BigDecimal.ZERO, BigDecimal::add)));
            demandPlanInfoDTO.setForecastPlanQtyLabel(DemandPlanTargetEnum.FORECAST_PLAN_QTY.getDesc());
            demandPlanInfoDTO.setForecastPlanQty(forecastPlanQty);
            // 设置上次确认量
            weekDateList.forEach(date -> lastConfirmQty.add(paramMap.get(key).stream().filter(item -> item.getPlanStartDate().compareTo(date.get(DemandPlanEnum.START_TIME.getColumns())) == 0 && item.getPlanEndDate().compareTo(date.get(DemandPlanEnum.END_TIME.getColumns())) == 0).map(DemandPlanDTO::getLastConfirmQty).reduce(BigDecimal.ZERO, BigDecimal::add)));
            demandPlanInfoDTO.setLastConfirmQtyLabel(DemandPlanTargetEnum.LAST_CONFIRM_QTY.getDesc());
            demandPlanInfoDTO.setLastConfirmQty(lastConfirmQty);
            // 安全库存量
            weekDateList.forEach(date -> safetyStockQty.add(paramMap.get(key).stream().filter(item -> item.getPlanStartDate().compareTo(date.get(DemandPlanEnum.START_TIME.getColumns())) == 0 && item.getPlanEndDate().compareTo(date.get(DemandPlanEnum.END_TIME.getColumns())) == 0).map(DemandPlanDTO::getSafetyStockQty).reduce(BigDecimal.ZERO, BigDecimal::add)));
            demandPlanInfoDTO.setSafetyStockQtyLabel(DemandPlanTargetEnum.SAFETY_STOCK_QTY.getDesc());
            demandPlanInfoDTO.setSafetyStockQty(safetyStockQty);
            //实际销量
            weekDateList.forEach(date -> actualSalesQty.add(paramMap.get(key).stream().filter(item -> item.getPlanStartDate().compareTo(date.get(DemandPlanEnum.START_TIME.getColumns())) == 0 && item.getPlanEndDate().compareTo(date.get(DemandPlanEnum.END_TIME.getColumns())) == 0).map(DemandPlanDTO::getActualSalesQty).reduce(BigDecimal.ZERO, BigDecimal::add)));
            demandPlanInfoDTO.setActualSalesQtyLabel(DemandPlanTargetEnum.ACTUAL_SALES_QTY.getDesc());
            demandPlanInfoDTO.setActualSalesQty(actualSalesQty);
            Date nowDate = DateUtil.beginOfDay(new Date());
            // 当前实时库存 只存当前周的数据其他数据给-1,前端显示-
            weekDateList.forEach(date -> {
                if (date.get(DemandPlanEnum.START_TIME.getColumns()).getTime() <= nowDate.getTime() &&
                        date.get(DemandPlanEnum.END_TIME.getColumns()).getTime() >= nowDate.getTime()) {
                    realTimeInventory.add(paramMap.get(key).stream().filter(item -> item.getPlanStartDate().compareTo(date.get(DemandPlanEnum.START_TIME.getColumns())) == 0 && item.getPlanEndDate().compareTo(date.get(DemandPlanEnum.END_TIME.getColumns())) == 0).map(DemandPlanDTO::getRealTimeInventoryQty).reduce(BigDecimal.ZERO, BigDecimal::add));
                    realTimeString.add(paramMap.get(key).stream().filter(item -> item.getPlanStartDate().compareTo(date.get(DemandPlanEnum.START_TIME.getColumns())) == 0 && item.getPlanEndDate().compareTo(date.get(DemandPlanEnum.END_TIME.getColumns())) == 0).map(DemandPlanDTO::getRealTimeInventoryQty).reduce(BigDecimal.ZERO, BigDecimal::add).toString());
                } else {
                    realTimeInventory.add(BigDecimal.ZERO);
                    realTimeString.add("-");
                }
            });
            demandPlanInfoDTO.setRealTimeInventoryLabel(DemandPlanTargetEnum.REAL_TIME_INVENTORY.getDesc());
            demandPlanInfoDTO.setRealTimeInventory(realTimeInventory);
            //获取渠道、区域、商品信息
            this.getInfoData(paramMap.get(key), demandPlanInfoDTO, demandPlan.getSkuCodeList(), demandPlan);
            demandPlantInfoList.add(demandPlanInfoDTO);
        });
        return demandPlantInfoList;
    }

    /**
     * 获取渠道、区域、商品信息
     *
     * @param demandPlanDTOS    需求计划dto
     * @param demandPlanInfoDTO 需求计划信息dto
     * @param skuCodeList       sku代码列表
     * @return {@link GmvTargetInfoDTO}
     */
    private DemandPlanInfoDTO getInfoData(List<DemandPlanDTO> demandPlanDTOS, DemandPlanInfoDTO demandPlanInfoDTO, List<String> skuCodeList, DemandPlanDTO demandPlan) {
        /**
         * 区域信息
         */
        demandPlanInfoDTO.setArea(
                demandPlanDTOS.stream().filter(item -> ObjectUtil.isNotNull(item.getProvinceName())).map(DemandPlanDTO::getProvinceName).distinct().collect(Collectors.joining()) +
                        demandPlanDTOS.stream().filter(item -> ObjectUtil.isNotNull(item.getCityName())).map(e -> "/" + e.getCityName()).distinct().collect(Collectors.joining()) +
                        demandPlanDTOS.stream().filter(item -> ObjectUtil.isNotNull(item.getCountyName())).map(e -> "/" + e.getCountyName()).distinct().collect(Collectors.joining()));
        // 渠道信息
        demandPlanInfoDTO.setChannel(
                demandPlanDTOS.stream().filter(item -> ObjectUtil.isNotNull(item.getChannelName())).map(DemandPlanDTO::getChannelName).distinct().collect(Collectors.joining()) +
                        demandPlanDTOS.stream().filter(item -> ObjectUtil.isNotNull(item.getSubChannelName())).map(e -> "/" + e.getSubChannelName()).distinct().collect(Collectors.joining()));
        // 品类信息
        demandPlanInfoDTO.setCategory(
                demandPlanDTOS.stream().filter(item -> ObjectUtil.isNotNull(item.getPriCategoryName())).map(DemandPlanDTO::getPriCategoryName).distinct().collect(Collectors.joining()) +
                        demandPlanDTOS.stream().filter(item -> ObjectUtil.isNotNull(item.getSecCategoryName())).map(e -> "/" + e.getSecCategoryName()).distinct().collect(Collectors.joining()) +
                        demandPlanDTOS.stream().filter(item -> ObjectUtil.isNotNull(item.getTerCategoryName())).map(e -> "/" + e.getTerCategoryName()).distinct().collect(Collectors.joining()));
        //sku信息
        if (CollectionUtils.isNotEmpty(skuCodeList)) {
            demandPlanInfoDTO.setSkuCode(demandPlanDTOS.stream().filter(item -> ObjectUtil.isNotNull(item.getSkuCode())).map(DemandPlanDTO::getSkuCode).distinct().collect(Collectors.joining()));
            demandPlanInfoDTO.setSkuName(demandPlanDTOS.stream().filter(item -> ObjectUtil.isNotNull(item.getSkuName())).map(DemandPlanDTO::getSkuName).distinct().collect(Collectors.joining()));
        }
        //一级渠道
        demandPlanInfoDTO.setChannelCode(demandPlanDTOS.get(0).getChannelCode());
        demandPlanInfoDTO.setSubChannelCode(demandPlanDTOS.get(0).getSubChannelCode());
        demandPlanInfoDTO.setPriCategoryCode(demandPlanDTOS.get(0).getPriCategoryCode());
        demandPlanInfoDTO.setSecCategoryCode(demandPlanDTOS.get(0).getSecCategoryCode());
        demandPlanInfoDTO.setTerCategoryCode(demandPlanDTOS.get(0).getTerCategoryCode());
        demandPlanInfoDTO.setStoreCode(CollectionUtils.isEmpty(demandPlan.getStoreCodeList()) ? "" : demandPlanDTOS.get(CommonConstants.ZERO).getStoreCode());
        demandPlanInfoDTO.setProvinceCode(demandPlanDTOS.get(0).getProvinceCode());
        demandPlanInfoDTO.setCityCode(demandPlanDTOS.get(0).getCityCode());
        demandPlanInfoDTO.setCountyCode(demandPlanDTOS.get(0).getCountyCode());
        return demandPlanInfoDTO;
    }

    /**
     * 设置分组依据的key值
     *
     * @param demandPlanDOS 需求计划dos
     * @param skuCodeList   sku代码列表
     * @return {@link List<DemandPlanDTO>}
     */
    public List<DemandPlanDTO> getGroupByKey(List<DemandPlanDTO> demandPlanDOS, List<String> skuCodeList, List<String> conditions) {
        demandPlanDOS.forEach(item -> {
            StringBuilder keyStr = new StringBuilder();
            StringBuilder keys = new StringBuilder();
            keyStr.append(ObjectUtil.isNull(item.getSubChannelCode()) ? item.getChannelCode() : "");
            keyStr.append(ObjectUtil.isNotNull(item.getSubChannelCode()) ? item.getSubChannelCode() : "");
            keyStr.append(ObjectUtil.isNotNull(item.getPriCategoryCode()) ? item.getPriCategoryCode() : "");
            keyStr.append(ObjectUtil.isNotNull(item.getSecCategoryCode()) ? item.getSecCategoryCode() : "");
            keyStr.append(ObjectUtil.isNotNull(item.getTerCategoryCode()) ? item.getTerCategoryCode() : "");
            keyStr.append(ObjectUtil.isNotNull(item.getProvinceCode()) ? item.getProvinceCode() : "");
            keyStr.append(ObjectUtil.isNotNull(item.getCityCode()) ? item.getCityCode() : "");
            keyStr.append(ObjectUtil.isNotNull(item.getCountyCode()) ? item.getCountyCode() : "");
            if (CollectionUtils.isNotEmpty(skuCodeList)) {
                keyStr.append(ObjectUtil.isNotNull(item.getSkuCode()) ? item.getSkuCode() : "");
            }
            keys.append(ObjectUtil.isNotNull(item.getPriCategoryCode()) ? item.getPriCategoryCode() : "");
            keys.append(ObjectUtil.isNotNull(item.getSecCategoryCode()) ? item.getSecCategoryCode() : "");
            keys.append(ObjectUtil.isNotNull(item.getTerCategoryCode()) ? item.getTerCategoryCode() : "");
            keys.append(ObjectUtil.isNotNull(item.getProvinceCode()) ? item.getProvinceCode() : "");
            keys.append(ObjectUtil.isNotNull(item.getCityCode()) ? item.getCityCode() : "");
            keys.append(ObjectUtil.isNotNull(item.getCountyCode()) ? item.getCountyCode() : "");
            if (CollectionUtils.isNotEmpty(skuCodeList)) {
                keys.append(ObjectUtil.isNotNull(item.getSkuCode()) ? item.getSkuCode() : "");
            }
            item.setPurchaseCondition(keys.toString());
            item.setCondition(keyStr.toString());
        });
        return demandPlanDOS;
    }


    /**
     * 根据获取的换算比例计算指标数量
     */
    public List<DemandPlanDTO>  calculationPro(List<DemandPlanDTO> resultList, List<SkuUnitDTO> skuUnitList) {
        skuUnitList.forEach(skuUnit -> {
            resultList.forEach(item -> {
                if (item.getSkuCode().equals(skuUnit.getSkuCode())) {
                    item.setSalesPlanQty(item.getSalesPlanQty().divide(BigDecimal.valueOf(skuUnit.getScale()),CommonConstants.SEVEN_DECIMAL,BigDecimal.ROUND_HALF_UP));
                    item.setForecastPlanQty(item.getForecastPlanQty().divide(BigDecimal.valueOf(skuUnit.getScale()),CommonConstants.SEVEN_DECIMAL,BigDecimal.ROUND_HALF_UP));
                    item.setLastConfirmQty(item.getLastConfirmQty().divide(BigDecimal.valueOf(skuUnit.getScale()),CommonConstants.SEVEN_DECIMAL,BigDecimal.ROUND_HALF_UP));
                }
            });
        });
        return resultList;
    }

    /**
     * 处理查询出来的条数和数据
     */
    public DemandPlanDO dealData(List<DemandPlanDO> list, DemandPlanDTO demandPlan) {
        //处理查询出来的数据
        //把查询的结果代入新的对象中，用于查询数据
        DemandPlanDO demandPlanDO = new DemandPlanDO();
        if (ObjectUtil.isNotEmpty(list)) {
            demandPlanDO.setChannelCode(list.get(0).getChannelCode());
            demandPlanDO.setSubChannelCode(list.get(0).getSubChannelCode());
            demandPlanDO.setProvinceCode(list.get(0).getProvinceCode());
            demandPlanDO.setCityCode(list.get(0).getCityCode());
            demandPlanDO.setCountyCode(list.get(0).getCountyCode());
            demandPlanDO.setPriCategoryCode(list.get(0).getPriCategoryCode());
            demandPlanDO.setSecCategoryCode(list.get(0).getSecCategoryCode());
            demandPlanDO.setTerCategoryCode(list.get(0).getTerCategoryCode());
            demandPlanDO.setSkuCode(list.get(0).getSkuCode());
            demandPlanDO.setStoreCode(list.get(0).getStoreCode());
            demandPlanDO.setDemandPlanDOS(list);
        }
        demandPlanDO.setStartTime(demandPlan.getStartTime());
        demandPlanDO.setEndTime(demandPlan.getEndTime());
        demandPlanDO.setLayeredCodeList(demandPlan.getLayeredCodeList());
        return demandPlanDO;
    }

    /**
     * excel每行数据设置 高级搜索  信息
     *
     * @param demandPlanInfoDTO
     * @param itemRow
     * @return void
     **/
    private void setExcelRowAdvancedSearchCondition(DemandPlanInfoDTO demandPlanInfoDTO, List<Object> itemRow) {
        if (!StringUtils.isEmpty(demandPlanInfoDTO.getChannel())) {
            itemRow.add(demandPlanInfoDTO.getChannel());
        }
        if (!StringUtils.isEmpty(demandPlanInfoDTO.getArea())) {
            itemRow.add(demandPlanInfoDTO.getArea());
        }
        if (!StringUtils.isEmpty(demandPlanInfoDTO.getCategory())) {
            itemRow.add(demandPlanInfoDTO.getCategory());
        }
        if (!StringUtils.isEmpty(demandPlanInfoDTO.getSkuName())) {
            itemRow.add(demandPlanInfoDTO.getSkuName());
        }
    }

    /**
     * 获取分组条件
     *
     * @param demandPlanDTO
     * @return
     */
    public List<String> getConditions(DemandPlanDTO demandPlanDTO) {
        List<String> conditions = new ArrayList<>();
        // if (CollectionUtils.isEmpty(demandPlanDTO.getSubChannelCodeList())) {
        //     conditions.add(BaseSearchColumnEnum.CHANNEL_CODE.getColumn());
        //     demandPlanDTO.setValidGmv(true);
        // }
        // if (CollectionUtils.isNotEmpty(demandPlanDTO.getSubChannelCodeList())) {
        //     conditions.add(BaseSearchColumnEnum.SUB_CHANNEL_CODE.getColumn());
        // }
        if (CollectionUtils.isNotEmpty(demandPlanDTO.getProvinceCodeList())) {
            demandPlanDTO.setValidGmv(true);
            conditions.add(BaseSearchColumnEnum.PROVINCE_CODE.getColumn());
        }
        if (CollectionUtils.isNotEmpty(demandPlanDTO.getCityCodeList())) {
            conditions.add(BaseSearchColumnEnum.CITY_CODE.getColumn());
        }
        if (CollectionUtils.isNotEmpty(demandPlanDTO.getCountyCodeList())) {
            conditions.add(BaseSearchColumnEnum.COUNTY_CODE.getColumn());
        }
        if (CollectionUtils.isNotEmpty(demandPlanDTO.getStoreCodeList())) {
            conditions.add(BaseSearchColumnEnum.STORE_CODE.getColumn());
        }
        if (!CollectionUtils.isEmpty(demandPlanDTO.getPriCategoryCodeList())) {
            demandPlanDTO.setValidGmv(true);
            conditions.add(BaseSearchColumnEnum.PRI_CATEGORY_CODE.getColumn());
        }
        if (CollectionUtils.isNotEmpty(demandPlanDTO.getSecCategoryCodeList())) {
            conditions.add(BaseSearchColumnEnum.SEC_CATEGORY_CODE.getColumn());
        }
        if (CollectionUtils.isNotEmpty(demandPlanDTO.getTerCategoryCodeList())) {
            conditions.add(BaseSearchColumnEnum.TER_CATEGORY_CODE.getColumn());
        }
        if (!CollectionUtils.isEmpty(demandPlanDTO.getSkuCodeList())) {
            conditions.add(BaseSearchColumnEnum.SKU_CODE.getColumn());
        }
        return conditions;
    }

    private int setExcelTitles(List<List<String>> heads, List<String> conditions, List<String> dateTitles) {
        //获取高级搜索标题
        this.getExcelAdvancedSearchTitle(heads, conditions);
        int result = heads.size();
        //加入指标标题
        List<String> targetTitle = new ArrayList<>();
        targetTitle.add(ExcelExportTitleEnum.TARGET_TITLE.getTitle());
        heads.add(targetTitle);
        //加入日期标题
        AdvancedSearchUtil.getExcelDateTitle(heads, dateTitles);
        return result;
    }

    /**
     * Excel表头
     *
     * @param heads
     * @param conditions
     */
    private void getExcelAdvancedSearchTitle(List<List<String>> heads, List<String> conditions) {
        if (conditions.contains(BaseSearchColumnEnum.CHANNEL_CODE.getColumn())) {
            setList(heads, ExcelExportTitleEnum.CHANNEL_TITLE.getTitle());
        }
        if (conditions.contains(BaseSearchColumnEnum.SUB_CHANNEL_CODE.getColumn())) {
            setList(heads, ExcelExportTitleEnum.CHANNEL_TITLE.getTitle());
        }
        if (conditions.contains(BaseSearchColumnEnum.PROVINCE_CODE.getColumn())) {
            setList(heads, ExcelExportTitleEnum.AREA_TITLE.getTitle());
        }
        if (conditions.contains(BaseSearchColumnEnum.CITY_CODE.getColumn())) {
            setList(heads, ExcelExportTitleEnum.AREA_TITLE.getTitle());
        }
        if (conditions.contains(BaseSearchColumnEnum.COUNTY_CODE.getColumn())) {
            setList(heads, ExcelExportTitleEnum.AREA_TITLE.getTitle());
        }
        if (conditions.contains(BaseSearchColumnEnum.STORE_CODE.getColumn())) {
            setList(heads, ExcelExportTitleEnum.AREA_TITLE.getTitle());
        }
        if (conditions.contains(BaseSearchColumnEnum.PRI_CATEGORY_CODE.getColumn())) {
            setList(heads, ExcelExportTitleEnum.CATEGORY_TITLE.getTitle());
        }
        if (conditions.contains(BaseSearchColumnEnum.SEC_CATEGORY_CODE.getColumn())) {
            setList(heads, ExcelExportTitleEnum.CATEGORY_TITLE.getTitle());
        }
        if (conditions.contains(BaseSearchColumnEnum.TER_CATEGORY_CODE.getColumn())) {
            setList(heads, ExcelExportTitleEnum.CATEGORY_TITLE.getTitle());
        }
        if (conditions.contains(BaseSearchColumnEnum.SKU_CODE.getColumn())) {
            setList(heads, ExcelExportTitleEnum.SKU_TITLE.getTitle());
        }
    }

    /**
     * 获取标题行list
     *
     * @param heads
     * @param title
     */
    private static void setList(List<List<String>> heads, String title) {
        List<String> list = new ArrayList<>();
        list.add(title);
        heads.add(list);
    }

    private List<BigDecimal> dealChartTarget(List<PlanPoInfoDTO> poInfoDTOS, List<BigDecimal> bigDecimalList, List<Map<String, Date>> weekDates, String type) {
        if (CollectionUtils.isEmpty(poInfoDTOS)) {
            weekDates.forEach(date -> bigDecimalList.add(BigDecimal.ZERO));
        } else {
            poInfoDTOS.stream().peek(item -> item.setCreateTime(DateUtil.beginOfWeek(item.getCreateTime())));
            if (DemandPlanTargetEnum.RESERVE_PURCHASE_QTY.getColumns().equals(type)) {
                weekDates.forEach(date -> {
                    BigDecimal reduce = poInfoDTOS.stream().filter(item -> item.getCreateTime().compareTo(date.get(DemandPlanEnum.START_TIME.getColumns())) == 0).
                            map(PlanPoInfoDTO::getAppointmentQty).reduce(BigDecimal.ZERO, BigDecimal::add);
                    bigDecimalList.add(reduce);
                });
            } else {
                weekDates.forEach(date -> {
                    BigDecimal reduce = poInfoDTOS.stream().filter(item -> item.getCreateTime().compareTo(date.get(DemandPlanEnum.START_TIME.getColumns())) == 0).
                            map(PlanPoInfoDTO::getNoFulfilPurchaseQty).reduce(BigDecimal.ZERO, BigDecimal::add);
                    bigDecimalList.add(reduce);
                });
            }

        }
        return bigDecimalList;
    }

    /**
     * 设置把对应的指标量放入到对应的分组的条件
     */
    public String groupKeys(List<String> conditions, DemandPlanInfoDTO demandPlanDTO) {
        StringBuilder groupKey = new StringBuilder();
        if (conditions.contains(BaseSearchColumnEnum.PRI_CATEGORY_CODE.getColumn())) {
            groupKey.append(demandPlanDTO.getPriCategoryCode());
        }
        if (conditions.contains(BaseSearchColumnEnum.SEC_CATEGORY_CODE.getColumn())) {
            groupKey.append(demandPlanDTO.getSecCategoryCode());
        }
        if (conditions.contains(BaseSearchColumnEnum.TER_CATEGORY_CODE.getColumn())) {
            groupKey.append(demandPlanDTO.getTerCategoryCode());
        }
        if (conditions.contains(BaseSearchColumnEnum.SKU_CODE.getColumn())) {
            groupKey.append(demandPlanDTO.getSkuCode());
        }
        if (conditions.contains(BaseSearchColumnEnum.PROVINCE_CODE.getColumn())) {
            groupKey.append(demandPlanDTO.getProvinceCode());
        }
        if (conditions.contains(BaseSearchColumnEnum.CITY_CODE.getColumn())) {
            groupKey.append(demandPlanDTO.getCityCode());
        }
        if (conditions.contains(BaseSearchColumnEnum.COUNTY_CODE.getColumn())) {
            groupKey.append(demandPlanDTO.getCountyCode());
        }
        if (conditions.contains(BaseSearchColumnEnum.STORE_CODE.getColumn())) {
            groupKey.append(demandPlanDTO.getStoreCode());
        }
        return groupKey.toString();
    }


    /**
     * 处理预约采购量和未履约采购量
     */
    private Map<String, Map<Date, BigDecimal>> dealAppointmentAndNoAgreement(List<PlanPoInfoDTO> poInfoDTOS, List<String> conditions, DemandPlanDTO demandPlan, String type) {
        if(CollectionUtils.isNotEmpty(poInfoDTOS)){
            //查询过来的数据，为14周的数据，先把数据都统一为每周的开始时间
            poInfoDTOS.stream().peek(item -> item.setCreateTime(DateUtil.beginOfWeek(item.getCreateTime()))).collect(Collectors.toList());
            //先把查询的结果按照省市区，或者对应的大中小品类以及sku或者门店进行分组
            Map<String, List<PlanPoInfoDTO>> listMap = poInfoDTOS.stream().collect(Collectors.groupingBy(item -> this.fetchGroupKey(demandPlan.getTerCodeMapping(), demandPlan.getWarehouseArea(), item, conditions), Collectors.toList()));
            //此时数据中存放着的是每组数据14周的数据
            Map<String, Map<Date, BigDecimal>> stringMapMap = this.deaPurchaseTarget(listMap, type, demandPlan);
            return stringMapMap;
        }
        return null;
    }


    private Map<String, Map<Date, BigDecimal>> deaPurchaseTarget(Map<String, List<PlanPoInfoDTO>> listMap, String type, DemandPlanDTO demandPlan) {
        //此时数据中存放着的是每组数据14周的数据
        Map<String, Map<Date, BigDecimal>> stringMap = new LinkedHashMap<>();
        if (DemandPlanTargetEnum.RESERVE_PURCHASE_QTY.getColumns().equals(type)) {
            listMap.forEach((k, v) -> {
                Map<Date, List<PlanPoInfoDTO>> dateListMap = v.stream().collect(Collectors.groupingBy(PlanPoInfoDTO::getCreateTime, Collectors.toList()));
                Map<Date, BigDecimal> appointmentQty = new LinkedHashMap<>();
                demandPlan.getWeekDateList().forEach(date -> {
                    //判断是否包含开始时间
                    if (dateListMap.containsKey(date.get(DemandPlanEnum.START_TIME.getColumns()))) {
                        List<PlanPoInfoDTO> planPoInfoDTOS = dateListMap.get(date.get(DemandPlanEnum.START_TIME.getColumns()));
                        appointmentQty.put(date.get(DemandPlanEnum.START_TIME.getColumns()), planPoInfoDTOS.stream().map(PlanPoInfoDTO::getAppointmentQty).reduce(BigDecimal.ZERO, BigDecimal::add));
                    } else {
                        appointmentQty.put(date.get(DemandPlanEnum.START_TIME.getColumns()), BigDecimal.ZERO);
                    }
                });
                stringMap.put(k, appointmentQty);
            });
        } else {
            listMap.forEach((k, v) -> {
                Map<Date, List<PlanPoInfoDTO>> dateListMap = v.stream().collect(Collectors.groupingBy(PlanPoInfoDTO::getCreateTime, Collectors.toList()));
                Map<Date, BigDecimal> noAgreementQty = new LinkedHashMap<>();
                demandPlan.getWeekDateList().forEach(date -> {
                    //判断是否包含开始时间
                    if (dateListMap.containsKey(date.get(DemandPlanEnum.START_TIME.getColumns()))) {
                        List<PlanPoInfoDTO> planPoInfoDTOS = dateListMap.get(date.get(DemandPlanEnum.START_TIME.getColumns()));
                        noAgreementQty.put(date.get(DemandPlanEnum.START_TIME.getColumns()), planPoInfoDTOS.stream().map(PlanPoInfoDTO::getNoFulfilPurchaseQty).reduce(BigDecimal.ZERO, BigDecimal::add));
                    } else {
                        noAgreementQty.put(date.get(DemandPlanEnum.START_TIME.getColumns()), BigDecimal.ZERO);
                    }
                });
                stringMap.put(k, noAgreementQty);
            });
        }
        return stringMap;
    }

    /**
     * 设置分组的条件
     */
    private String fetchGroupKey(Map<Long, String> terCodeMapping, Map<String, String> warehouseArea, PlanPoInfoDTO item, List<String> conditions) {
        StringBuilder groupKey = new StringBuilder();
        //如果品类不为空，拿到对应的大品类，中品类或者是小品类
        if (terCodeMapping != null && terCodeMapping.size() > 0) {
            groupKey.append(terCodeMapping.get(item.getCategory()));
        }
        //如果sku不为空,拿到对应的sku
        if (conditions.contains(BaseSearchColumnEnum.SKU_CODE.getColumn())) {
            groupKey.append(item.getSkuCode());
        }
        //如果区域不为空，拿到对应的门店，省，市，或者是区
        if (ObjectUtil.isNotEmpty(warehouseArea)) {
            groupKey.append(warehouseArea.get(item.getWarehouseCode()));
        }
        return groupKey.toString();
    }


    /**
     * 处理单位转换的问题
     *
     * @param planPoQueryDTOS
     * @param unitType
     * @return {@link List<PlanPoInfoDTO>}
     */
    private List<PlanPoInfoDTO> dealPurchaseUnitType(List<PlanPoInfoDTO> planPoQueryDTOS, Long unitType, String type) {
        if (CollectionUtils.isNotEmpty(planPoQueryDTOS)) {
            //知道自身是采购单位，先转换为基本单位
            List<String> skuCodes = planPoQueryDTOS.stream().map(PlanPoInfoDTO::getSkuCode).distinct().collect(Collectors.toList());
            //如果前端查询的是采购单位
            if (SkuUnitTypeEnum.PURCHASE_UNIT.getUnitType().equals(unitType)) {
                return planPoQueryDTOS;
            }
            //处理单位,查询出采购单位的比例
            List<SkuUnitDTO> conversionRatio = itemCoreFacade.getConversionRatio(skuCodes, SkuUnitTypeEnum.PURCHASE_UNIT.getUnitType());
            //处理单位，查询出当前用户选择的单位
            List<SkuUnitDTO> unitDTOS = itemCoreFacade.getConversionRatio(skuCodes, unitType);
            //把结果处理为基本单位
            this.dealUnit(planPoQueryDTOS, unitType, type, conversionRatio, unitDTOS);
        }
        return planPoQueryDTOS;
    }

    private List<PlanPoInfoDTO> dealUnit(List<PlanPoInfoDTO> planPoQueryDTOS, Long unitType, String type, List<SkuUnitDTO> conversionRatio, List<SkuUnitDTO> unitDTOS) {
        if (DemandPlanTargetEnum.RESERVE_PURCHASE_QTY.getColumns().equals(type)) {
            //把结果处理为基本单位
            planPoQueryDTOS.forEach(item -> {
                conversionRatio.forEach(skuUnitDTO -> {
                    if (item.getSkuCode().equals(skuUnitDTO.getSkuCode())) {
                        //把预约在途采购量和未履约采购量换成基本单位的数量
                        item.setAppointmentQty(item.getAppointmentQty().multiply(BigDecimal.valueOf(skuUnitDTO.getScale())).setScale(CommonConstants.SEVEN_DECIMAL,BigDecimal.ROUND_HALF_UP ).stripTrailingZeros());
                    }
                });
            });
            //把结果处理为用户选择的单位
            planPoQueryDTOS.forEach(item -> {
                unitDTOS.forEach(skuUnitDTO -> {
                    if (item.getSkuCode().equals(skuUnitDTO.getSkuCode())) {
                        item.setAppointmentQty(item.getAppointmentQty().divide(BigDecimal.valueOf(skuUnitDTO.getScale()),CommonConstants.SEVEN_DECIMAL,BigDecimal.ROUND_HALF_UP));

                    }
                });
            });
        } else {
            planPoQueryDTOS.forEach(item -> {
                conversionRatio.forEach(skuUnitDTO -> {
                    if (item.getSkuCode().equals(skuUnitDTO.getSkuCode())) {
                        //把预约在途采购量和未履约采购量换成基本单位的数量
                        item.setNoFulfilPurchaseQty(item.getNoFulfilPurchaseQty().multiply(BigDecimal.valueOf(skuUnitDTO.getScale())).setScale(CommonConstants.SEVEN_DECIMAL,BigDecimal.ROUND_HALF_UP).stripTrailingZeros());
                    }
                });
            });
            //把结果处理为用户选择的单位
            planPoQueryDTOS.forEach(item -> {
                unitDTOS.forEach(skuUnitDTO -> {
                    if (item.getSkuCode().equals(skuUnitDTO.getSkuCode())) {
                        //把预约在途采购量和未履约采购量换成基本单位的数量
                        item.setNoFulfilPurchaseQty(item.getNoFulfilPurchaseQty().divide(BigDecimal.valueOf(skuUnitDTO.getScale()),CommonConstants.SEVEN_DECIMAL,BigDecimal.ROUND_HALF_UP));
                    }
                });
            });
        }
        return planPoQueryDTOS;
    }

    /**
     * 处理查询参数的问题
     *
     * @param demandPlan 需求计划
     * @return {@link DemandPlanDTO}
     */
    public PlanPoQueryDTO dealCategoryCode(DemandPlanDTO demandPlan, List<DemandPlanDTO> demandPlanDOS, List<String> conditions) {
        PlanPoQueryDTO planPoQueryDTO = new PlanPoQueryDTO();
        planPoQueryDTO.setStartTime(demandPlan.getStartTime());
        planPoQueryDTO.setEndTime(DateUtil.endOfDay(demandPlan.getEndTime()));
        //大品类
        if (conditions.contains(BaseSearchColumnEnum.PRI_CATEGORY_CODE.getColumn())) {
            List<String> priCategoryCodeList = demandPlanDOS.stream().map(DemandPlanDTO::getPriCategoryCode).distinct().collect(Collectors.toList());
            //根据大品类获取中品类
            List<CategoryBaseInfoDTO> categoryBaseInfoDTOS = itemCoreFacade.listByCategoryCodes(priCategoryCodeList);
            //获取大品类id--code
            Map<Long, String> priCode = categoryBaseInfoDTOS.stream().collect(Collectors.toMap(CategoryBaseInfoDTO::getId, item -> item.getCode().toString()));
            //获取所有的中品类，再根据中品类获取小品类
            List<String> secCategoryCodeList = categoryBaseInfoDTOS.stream().map(CategoryBaseInfoDTO::getCategoryDTOList).
                    flatMap(pList -> pList.stream()).map(item -> item.getCode().toString()).collect(Collectors.toList());
            //根据中品类获取小品类
            List<CategoryBaseInfoDTO> infoDTOS = itemCoreFacade.listByCategoryCodes(secCategoryCodeList);
            List<Long> terCategoryCodeList = infoDTOS.stream().map(CategoryBaseInfoDTO::getCategoryDTOList).
                    flatMap(pList -> pList.stream()).map(item -> item.getCode()).collect(Collectors.toList());
            planPoQueryDTO.setTerCategoryCodes(terCategoryCodeList);
            //获取中品类id--code
            Map<Long, Long> secId = infoDTOS.stream().collect(Collectors.toMap(CategoryBaseInfoDTO::getId, CategoryBaseInfoDTO::getParentId));
            //获取大品类code和小品类code一一对应
            Map<Long, String> terCodeMapping = infoDTOS.stream().map(CategoryBaseInfoDTO::getCategoryDTOList).flatMap(pList -> pList.stream()).
                    collect(Collectors.toMap(item -> item.getCode(), item -> priCode.get(secId.get(item.getParentId()))));
            demandPlan.setTerCodeMapping(terCodeMapping);
        }
        //中品类
        if (conditions.contains(BaseSearchColumnEnum.SEC_CATEGORY_CODE.getColumn())) {
            List<String> secCategoryCodeList = demandPlanDOS.stream().map(DemandPlanDTO::getSecCategoryCode).distinct().collect(Collectors.toList());
            List<CategoryBaseInfoDTO> categoryBaseInfoDTOS = itemCoreFacade.listByCategoryCodes(secCategoryCodeList);
            //获取中品类id--code
            Map<Long, String> secIdCode = categoryBaseInfoDTOS.stream().collect(Collectors.toMap(CategoryBaseInfoDTO::getId, item -> item.getCode().toString()));
            //帅选出所有的小品类
            List<Long> terCategoryCodeList = categoryBaseInfoDTOS.stream().map(CategoryBaseInfoDTO::getCategoryDTOList).
                    flatMap(pList -> pList.stream()).map(item -> item.getCode()).collect(Collectors.toList());
            planPoQueryDTO.setTerCategoryCodes(terCategoryCodeList);
            //把小品类的code和中品类的code对应，然后放入到对应的对象中
            Map<Long, String> terCodeMapping = categoryBaseInfoDTOS.stream().map(CategoryBaseInfoDTO::getCategoryDTOList).flatMap(pList -> pList.stream()).
                    collect(Collectors.toMap(item -> item.getCode(), item -> secIdCode.get(item.getParentId())));
            demandPlan.setTerCodeMapping(terCodeMapping);
        }
        //小品lie
        if (conditions.contains(BaseSearchColumnEnum.TER_CATEGORY_CODE.getColumn())) {
            List<String> terCategoryCodeList = demandPlanDOS.stream().map(DemandPlanDTO::getTerCategoryCode).distinct().collect(Collectors.toList());
            planPoQueryDTO.setTerCategoryCodes(terCategoryCodeList.stream().map(item -> Long.valueOf(item)).collect(Collectors.toList()));
            Map<Long, String> terCodeMapping = terCategoryCodeList.stream().collect(Collectors.toMap(item -> Long.valueOf(item), item -> item));
            demandPlan.setTerCodeMapping(terCodeMapping);
        }
        //sku
        if (conditions.contains(BaseSearchColumnEnum.SKU_CODE.getColumn())) {
            //把skuCode作为筛选条件带出，因为这里存在着商品分层的结果
            List<String> skuCodes = demandPlanDOS.stream().map(DemandPlanDTO::getSkuCode).distinct().collect(Collectors.toList());
            planPoQueryDTO.setSkuCodes(skuCodes);
        }
        Map<String, String> warehouseArea = new HashMap<>();
        //设置仓库查询条件
        List<String> warehouseCodes = new ArrayList<>();
        //查询参数
        RealWarehouseParamDTO warehouseParamDTO = new RealWarehouseParamDTO();
        List<RealWarehouseAreaAddDTO> areaAddDTOList = new ArrayList<>();
        /**
         * 根据省市区批量查询仓库的code,然后把仓库和对应的省市区放入到和仓库一一对应的map，用来分组
         * 从采购查询到的数据
         */
        //根据省查询仓库
        if (conditions.contains(BaseSearchColumnEnum.PROVINCE_CODE.getColumn())) {
            demandPlanDOS.forEach(item -> {
                RealWarehouseAreaAddDTO areaAddDTO = new RealWarehouseAreaAddDTO();
                areaAddDTO.setProvinceCode(item.getProvinceCode());
                areaAddDTOList.add(areaAddDTO);
            });
            warehouseParamDTO.setRealWarehouseAreaAddDTOList(areaAddDTOList);
            List<RealWarehouse> realWarehouses = stockCoreFacade.queryForAdmin(warehouseParamDTO);
            warehouseCodes.addAll(realWarehouses.stream().map(RealWarehouse::getFactoryCode).distinct().collect(Collectors.toList()));
            Map<String, RealWarehouse> realWarehouseMap = realWarehouses.stream().filter(item -> ObjectUtil.isNotEmpty(item.getRealWarehouseProvinceCode())).
                    collect(Collectors.toMap(RealWarehouse::getFactoryCode, Function.identity(), (real1, real2) -> real2));
            for (String key : realWarehouseMap.keySet()) {
                warehouseArea.put(key, realWarehouseMap.get(key).getRealWarehouseProvinceCode());
            }
        }
        //根据市查询仓库
        if (conditions.contains(BaseSearchColumnEnum.CITY_CODE.getColumn())) {
            demandPlanDOS.forEach(item -> {
                RealWarehouseAreaAddDTO areaAddDTO = new RealWarehouseAreaAddDTO();
                areaAddDTO.setCityCode(item.getCityCode());
                areaAddDTOList.add(areaAddDTO);
            });
            warehouseParamDTO.setRealWarehouseAreaAddDTOList(areaAddDTOList);
            List<RealWarehouse> realWarehouses = stockCoreFacade.queryForAdmin(warehouseParamDTO);
            warehouseCodes.addAll(realWarehouses.stream().map(RealWarehouse::getFactoryCode).distinct().collect(Collectors.toList()));
            Map<String, RealWarehouse> realWarehouseMap = realWarehouses.stream().filter(item -> ObjectUtil.isNotEmpty(item.getRealWarehouseCityCode())).
                    collect(Collectors.toMap(RealWarehouse::getFactoryCode, Function.identity(), (real1, real2) -> real2));
            for (String key : realWarehouseMap.keySet()) {
                warehouseArea.put(key, realWarehouseMap.get(key).getRealWarehouseCityCode());
            }
        }
        //根据区查询仓库
        if (conditions.contains(BaseSearchColumnEnum.COUNTY_CODE.getColumn())) {
            demandPlanDOS.forEach(item -> {
                RealWarehouseAreaAddDTO areaAddDTO = new RealWarehouseAreaAddDTO();
                areaAddDTO.setAreaCode(item.getCountyCode());
                areaAddDTOList.add(areaAddDTO);
            });
            warehouseParamDTO.setRealWarehouseAreaAddDTOList(areaAddDTOList);
            List<RealWarehouse> realWarehouses = stockCoreFacade.queryForAdmin(warehouseParamDTO);
            warehouseCodes.addAll(realWarehouses.stream().map(RealWarehouse::getFactoryCode).distinct().collect(Collectors.toList()));
            Map<String, RealWarehouse> realWarehouseMap = realWarehouses.stream().filter(item -> ObjectUtil.isNotEmpty(item.getRealWarehouseAreaCode())).
                    collect(Collectors.toMap(RealWarehouse::getFactoryCode, Function.identity(), (real1, real2) -> real2));
            for (String key : realWarehouseMap.keySet()) {
                warehouseArea.put(key, realWarehouseMap.get(key).getRealWarehouseAreaCode());
            }
        }
        //根据门店查询
        if (conditions.contains(BaseSearchColumnEnum.STORE_CODE.getColumn())) {
            warehouseCodes = demandPlanDOS.stream().map(DemandPlanDTO::getStoreCode).distinct().collect(Collectors.toList());
            warehouseArea = warehouseCodes.stream().collect(Collectors.toMap(item -> item, item -> item));
        }
        planPoQueryDTO.setWarehouseCodes(warehouseCodes);
        demandPlan.setWarehouseArea(warehouseArea);
        return planPoQueryDTO;
    }

    public void handleBigData(List<BigDataGeneralInfoDTO> bigDataGeneralInfoDTOs, String opSign, String storeCode,Date startDate) {
        if (!CollectionUtils.isEmpty(bigDataGeneralInfoDTOs)) {
            List<List<BigDataGeneralInfoDTO>> lists = splitTo(bigDataGeneralInfoDTOs, 2000);
            for (List<BigDataGeneralInfoDTO> list : lists) {
                demandPlanRepository.updateSafetyStockById(list, opSign, storeCode,startDate);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void handleRemedialBigData(List<BigDataGeneralInfoDTO> bigDataGeneralInfoDTOs, String opSign, String storeCode,Date startDate) {
        if (!CollectionUtils.isEmpty(bigDataGeneralInfoDTOs)) {
            List<List<BigDataGeneralInfoDTO>> lists = splitTo(bigDataGeneralInfoDTOs, 5000);
            for (List<BigDataGeneralInfoDTO> list : lists) {
                demandPlanRepository.updateSafetyStockById(list, opSign, storeCode,startDate);
            }
        }
        //删除错误日志信息
        operationLogRecordRepository.deleteBigDataErrorLog(OperationDataEnum.PLAN_DEMAND.getTableType(), startTime, endTime, storeCode);
    }
    @Override
    public void delete(String opSign) {
        demandPlanRepository.delete(opSign);
    }
}
